package com.securitydome04.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


@Configuration
@EnableWebSecurity
public class SecurityConfig {

    //工厂
    @Bean
    public LoginFilter loginFilter() throws Exception {
        LoginFilter loginFilter = new LoginFilter();
        //传入接受的参数名
        loginFilter.setUsernameParameter("uname");
        loginFilter.setPasswordParameter("pwd");
        loginFilter.setFilterProcessesUrl("/doLogin");
        loginFilter.setAuthenticationManager(authenticationManager(null));

        loginFilter.setAuthenticationSuccessHandler(((request, response, authentication) -> {
            Map<String, Object> result=new HashMap<>();
            result.put("msg","登陆成功！");
            result.put("authentication",authentication.getPrincipal());
//            SecurityContextHolder.getContext().setAuthentication(authentication);
            //相应状态码
            response.setStatus(HttpStatus.OK.value());
            response.setContentType("application/json;charset=UTF-8");
            String s = new ObjectMapper().writeValueAsString(result);
            response.getWriter().println(s);
        }));

        loginFilter.setAuthenticationFailureHandler(((request, response, exception) -> {
            Map<String, Object> result=new HashMap<>();
            result.put("msg","登陆失败："+exception.getMessage());

            //相应状态码
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            response.setContentType("application/json;charset=UTF-8");
            String s = new ObjectMapper().writeValueAsString(result);
            response.getWriter().println(s);
        }));
        return loginFilter;
    }


    //配置用户信息
    @Bean
    public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
        AuthenticationManagerBuilder builder = http.getSharedObject(AuthenticationManagerBuilder.class);
        builder.userDetailsService(userDetailsService());
        //v.passwordEncoder(mypasswordEncoder());
        return builder.build();
    }


    //配置数据源
    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
        inMemoryUserDetailsManager.createUser(User.withUsername("root").password("{noop}123").username("admin").build());
        return inMemoryUserDetailsManager;
    }


    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http.csrf(AbstractHttpConfigurer::disable);

        //拦截处理
        http.authorizeHttpRequests(authz -> authz
                .requestMatchers("/doLogin").permitAll()  // 允许所有用户访问的页面
                .anyRequest().authenticated()  // 其他所有请求都需要认证
        );
        //at将后面的过滤器替换掉
        //after放在那个过滤器之后
        //before放在那个过滤器之前
        http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);

        //认证信息
        http.addFilterBefore(new SecurityContextPersistenceFilter(), UsernamePasswordAuthenticationFilter.class);

        //开启拦截转跳自定义页面
//        http.formLogin(form->form
//                .toString()
//        );

        //


        //异常处理
        http.exceptionHandling(exc->exc
                .authenticationEntryPoint(((request, response, authException) -> {
                    response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
                    response.getWriter().println("认证后来访问");
                }))
        );


        //登出处理
        http.logout(logout->logout
                .logoutSuccessHandler((new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        Map<String, Object> result=new HashMap<>();
                        result.put("msg","退出成功："+authentication);
                        response.setContentType("application/json;charset=UTF-8");
                        response.setStatus(HttpStatus.OK.value());
                        String s = new ObjectMapper().writeValueAsString(result);
                        response.getWriter().println(s);
                    }
                }))
        );


        return http.build();
    }



}
